home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 16 code / CollaboDraw / draw.window.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-24  |  42.1 KB  |  1,809 lines  |  [TEXT/MPS ]

  1. /*-------------------------------------------------------------------------------------
  2.  *
  3.  * Simple Sample PowerTalk Application Framework
  4.  *
  5.  * ©1991-1993 Apple Computer
  6.  *
  7.  -------------------------------------------------------------------------------------*/
  8. /*
  9.  * draw.window.c -- window class instantiation/dispatching
  10.  *
  11.  * change history:
  12.  *
  13.  * SJF        08/23/93        1.0f1        update to final headers, fix comments
  14.  * SJF        04/21/93        1.0b2        update to b2
  15.  * SJF        03/01/93        1.0b1        added digital signatures
  16.  * SJF        02/09/93        1.0b1        update to b1
  17.  * SJF        10/13/92        1.0d4        update to a11
  18.  * SJF        09/09/92        1.0d3        update to a9
  19.  * SJF        05/07/92        1.0d2        update to a6
  20.  * SJF        11/06/91        1.0d1        initial coding
  21.  *
  22.  */
  23.  
  24. #ifndef __TYPES__
  25. #include <Types.h>
  26. #endif
  27.  
  28. #ifndef __QUICKDRAW__
  29. #include <QuickDraw.h>
  30. #endif
  31.  
  32. #ifndef __WINDOWS__
  33. #include <Windows.h>
  34. #endif
  35.  
  36. #ifndef __MENUS__
  37. #include <Menus.h>
  38. #endif
  39.  
  40. #ifndef __FILES__
  41. #include <Files.h>
  42. #endif
  43.  
  44. #ifndef __SCRIPT__
  45. #include <Script.h>
  46. #endif
  47.  
  48. #ifndef __ERRORS__
  49. #include <Errors.h>
  50. #endif
  51.  
  52. #ifndef __FOLDERS__
  53. #include <Folders.h>
  54. #endif
  55.  
  56. #ifdef THINK_C
  57. #include <BDC.h>    //workaround for problem with Think's packages.h
  58. #endif
  59.  
  60. #ifndef __PACKAGES__
  61. #include <Packages.h>
  62. #endif
  63.  
  64. #ifndef __OCESTANDARDMAIL__
  65. #include <OCEStandardMail.h>
  66. #endif
  67.  
  68. #ifndef __RESOURCES__
  69. #include <Resources.h>
  70. #endif
  71.  
  72. #include "const.h"
  73. #include "strconst.h"
  74. #include "mytypes.h"
  75. #include "globals.h"
  76. #include "utils.h"
  77. #include "windowstuff.h"
  78. #include "mymenus.h"
  79. #include "digisig.h"
  80. #include "base.window.h"
  81. #include "windutils.h"
  82.  
  83. #include "draw.window.h"
  84.  
  85. #define kLineSlop        5
  86. #define    kSlop            2
  87. #define    kAnchorWidth    2
  88.  
  89. /* instantiate a new draw window */
  90.  
  91. WindowPtr DrawMakeWindow(Rect *wRect,StringPtr title,Boolean visible,short wdefProc,
  92.                             Boolean goAwayFlag)
  93. {
  94.     WInfoPtr infoPtr;
  95.     WindowPtr theWindow;
  96.     char hState;
  97.     
  98.     theWindow = BaseMakeWindow(wRect,title,visible,wdefProc,goAwayFlag);
  99.     SetWindowKind(theWindow,kDrawWindow);
  100.  
  101.     infoPtr = BeginWindowAccess(theWindow,&hState);
  102.     
  103.     SetDrawMethods(infoPtr);
  104.     
  105.     // set other window information
  106.     infoPtr->data = nil;
  107.     infoPtr->otherData[kDSIGData] = nil;
  108.     
  109.     // make scroll bars
  110.     MakeScrollBars(theWindow,infoPtr);
  111.     
  112.     EndWindowAccess(theWindow,hState);
  113.     
  114.     return theWindow;
  115. }
  116.  
  117.  
  118. /* set up the method pointers for the drawing window class (may be called when a mailer
  119.    gets added/removed
  120. */
  121. void SetDrawMethods(WInfoPtr infoPtr)
  122. {
  123.     infoPtr->m_idle = BaseIdleWindow;
  124.     infoPtr->m_fixCursor = DrawFixCursorWindow;
  125.     infoPtr->m_activate = DrawActivateWindow;
  126.     infoPtr->m_deactivate = DrawDeactivateWindow;
  127.     infoPtr->m_update = DrawUpdateWindow;
  128.     infoPtr->m_key = BaseKeyWindow;
  129.     infoPtr->m_resize = DrawResizeWindow;
  130.     infoPtr->m_click = DrawClickWindow;
  131.     infoPtr->m_destroy = DrawDestroyWindow;
  132.     infoPtr->m_undo = DrawUndoWindow;
  133.     infoPtr->m_cut = BaseCutWindow;
  134.     infoPtr->m_copy = BaseCopyWindow;
  135.     infoPtr->m_paste = BasePasteWindow;
  136.     infoPtr->m_clear = BaseClearWindow;
  137.     infoPtr->m_print = DrawPrintWindow;
  138.     infoPtr->m_pageSetup = DrawPageSetupWindow;
  139.     infoPtr->m_save = DrawSaveWindow;
  140.     infoPtr->m_load = DrawLoadWindow;
  141.     infoPtr->m_event = BaseEventWindow;
  142.     infoPtr->m_ctrlHit = DrawHitControlWindow;
  143.     infoPtr->m_selectAll = DrawSelectAllWindow;
  144.     infoPtr->m_group = DrawGroupWindow;
  145.     infoPtr->m_unGroup = DrawUnGroupWindow;
  146. }
  147.  
  148.  
  149. /* handle mouse-moved events for draw window */
  150.  
  151. void *DrawFixCursorWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  152. {
  153.     RgnHandle returnRgn;
  154.     unsigned long *crsrData;
  155.     RgnHandle arrowRgn,pencilRgn;
  156.     Point offsetPt,mousePt;
  157.     GrafPtr savePort;
  158.     Rect drawRect;
  159.     
  160.     GetPort(&savePort);
  161.     SetPort(window);
  162.         
  163.     crsrData = (unsigned long *)data;
  164.     returnRgn = (RgnHandle)crsrData[1];
  165.     mousePt = *(Point *)&crsrData[0];
  166.     arrowRgn = NewRgn();
  167.     pencilRgn = NewRgn();
  168.     
  169.     drawRect = window->portRect;
  170.     drawRect.bottom -= 15;
  171.     drawRect.right -= 15;
  172.     
  173.     SetRectRgn(arrowRgn,-32768,-32768,32767,32767);
  174.     RectRgn(pencilRgn,&drawRect);
  175.     SetPt(&offsetPt,0,0);
  176.     LocalToGlobal(&offsetPt);
  177.     OffsetRgn(pencilRgn,offsetPt.h,offsetPt.v);
  178.     DiffRgn(arrowRgn,pencilRgn,arrowRgn);
  179.     
  180.     if (PtInRgn(mousePt,arrowRgn)) {
  181.         CopyRgn(arrowRgn,returnRgn);
  182.         SetCursor(&qd.arrow);
  183.     }
  184.     else if (PtInRgn(mousePt,pencilRgn)) {
  185.         CopyRgn(pencilRgn,returnRgn);
  186.         if (gCurrentShape!=kSelectShape)
  187.             SetCursor(&gPencilCursor);
  188.         else
  189.             SetCursor(&qd.arrow);
  190.     }
  191.  
  192.         
  193.     DisposeRgn(arrowRgn);
  194.     DisposeRgn(pencilRgn);
  195.     SetPort(savePort);
  196.     
  197.     return BaseFixCursorWindow(window,infoPtr,data);
  198. }
  199.  
  200.  
  201. /* deallocate any memory associated with the draw window class */
  202.  
  203. void *DrawDestroyWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  204. {
  205.     ShapeListPtr shapeList,prevShape;
  206.     OSErr err;
  207.     
  208.     DSIGCloseFile(infoPtr);
  209.     
  210.     if (infoPtr->fRefNum) {
  211.         err = FSClose(infoPtr->fRefNum);
  212.         if (err!=noErr)
  213.             DoError(err);
  214.         infoPtr->fRefNum = 0;
  215.     }
  216.     
  217.     if (infoPtr->resRefNum) {
  218.         CloseResFile(infoPtr->resRefNum);
  219.         err = ResError();
  220.         if (err!=noErr)
  221.             DoError(err);
  222.         infoPtr->resRefNum = 0;
  223.     }
  224.         
  225.     shapeList = (ShapeListPtr) infoPtr->data;
  226.     while (shapeList) {
  227.         prevShape = shapeList;
  228.         shapeList = shapeList->next;
  229.         DisposPtrChk(prevShape);
  230.     }
  231.     
  232.     DisposeControl(VSCROLL);
  233.     DisposeControl(HSCROLL);
  234.     
  235.     return BaseDestroyWindow(window,infoPtr,data);
  236. }
  237.  
  238.  
  239. /* handle undo for draw window */
  240.  
  241. void *DrawUndoWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  242. {
  243.     #pragma unused (data)
  244.     if (!gCanUndo || window!=gUndoCommand.window) {
  245.         DoError(kInternalError);
  246.         return nil;
  247.     }
  248.     
  249.     if (gHasUndo) {    // we should redo
  250.         AddShape(gUndoCommand.theShape.shapeType,gUndoCommand.theShape.anchor,
  251.                 gUndoCommand.theShape.destination,nil,(ShapeListPtr *)&infoPtr->data,false);
  252.         InvalShapeArea(window,infoPtr,(ShapeListPtr)infoPtr->data);
  253.         gHasUndo = false;
  254.     }
  255.     else {
  256.         RemoveTopShape(window,infoPtr);
  257.         gHasUndo = true;
  258.     }
  259.     
  260.     SetupAppUndo();
  261.     return nil;
  262. }
  263.  
  264.  
  265. /* handle activate events for draw window */
  266.  
  267. void *DrawActivateWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  268. {
  269.     MenuHandle theMenu;
  270.     
  271.     DisableAllMenus();
  272.     
  273.     theMenu = GetMHandle(kFileMenu);
  274.     EnableAllMenuItems(theMenu);
  275.     if (!infoPtr->changed)
  276.         DisableItem(theMenu,kSaveItem);
  277.             
  278.     /* only enable mail menu if we have Standard Mail available */
  279.     
  280.     if (gHasStandardMail) {
  281.         theMenu = GetMHandle(kMailMenu);
  282.         EnableAllMenuItems(theMenu);
  283.         DisableItem(theMenu,kSendItem);
  284.         DisableItem(theMenu,kReplyItem);
  285.         DisableItem(theMenu,kReplyToAllItem);
  286.         DisableItem(theMenu,kForwardItem);
  287.         DisableItem(theMenu,kTagLetterItem);
  288.     }
  289.     
  290.     FixDrawMenus(infoPtr);
  291.     
  292.     gMenusDirty = true;
  293.  
  294.     HiliteControl(VSCROLL,0);
  295.     HiliteControl(HSCROLL,0);
  296.  
  297.     return BaseActivateWindow(window,infoPtr,data);
  298. }
  299.  
  300.  
  301. /* handle deactivate events for draw window */
  302.  
  303. void *DrawDeactivateWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  304. {
  305.     HiliteControl(VSCROLL,254);
  306.     HiliteControl(HSCROLL,254);
  307.  
  308.     return BaseDeactivateWindow(window,infoPtr,data);
  309. }
  310.  
  311.  
  312. /* handle mouse click in content for draw window */
  313.  
  314. void *DrawClickWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  315. {
  316.     GrafPtr savePort;
  317.     RgnHandle saveRgn,windowRgn;
  318.     MenuHandle theMenu;
  319.     Boolean changed;
  320.     
  321.     changed = false;
  322.     
  323.     GetPort(&savePort);
  324.     SetPort(window);
  325.  
  326.     windowRgn = GetScrollersRgn(&window->portRect);
  327.     
  328.     saveRgn = NewRgn();
  329.     GetClip(saveRgn);
  330.     DiffRgn(saveRgn,windowRgn,windowRgn);
  331.     SetClip(windowRgn);
  332.  
  333.     if (gCurrentShape==kSelectShape) {
  334.         changed = WarpExistingShape(window,infoPtr,((EventRecord *)data)->where,
  335.             (((EventRecord *)data)->modifiers & shiftKey)!=0);
  336.         if (changed)
  337.             ClearAppUndo();
  338.     }
  339.     else {
  340.         EnterNewShape(window,infoPtr,((EventRecord *)data)->where);
  341.         changed = true;
  342.     }
  343.     
  344.     SetClip(saveRgn);
  345.     DisposeRgn(saveRgn);    
  346.     DisposeRgn(windowRgn);
  347.     SetPort(savePort);
  348.  
  349.     FixDrawMenus(infoPtr);
  350.     theMenu = GetMHandle(kFileMenu);    // now we've changed, so the user can save
  351.     EnableItem(theMenu,kSaveItem);
  352.     
  353.     infoPtr->changed |= changed;
  354.     return nil;
  355. }
  356.  
  357.  
  358. /* handle update events for draw window */
  359.  
  360. void *DrawUpdateWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  361. {
  362.     RgnHandle saveRgn,windowRgn;
  363.     Point *scrollPos,offsetPos;
  364.     
  365.     scrollPos = (Point*)&infoPtr->otherData[kViewOffset];
  366.     offsetPos.h = infoPtr->leftIndent - scrollPos->h;
  367.     offsetPos.v = infoPtr->topIndent - scrollPos->v;
  368.     
  369.     saveRgn = NewRgn();
  370.     windowRgn = GetScrollersRgn(&window->portRect);
  371.  
  372.     GetClip(saveRgn);
  373.     DiffRgn(saveRgn,windowRgn,windowRgn);
  374.     SetClip(windowRgn);
  375.     
  376.     DrawAllShapes(infoPtr,offsetPos);
  377.     
  378.     SetClip(saveRgn);
  379.     DisposeRgn(saveRgn);
  380.     DisposeRgn(windowRgn);
  381.     
  382.     UpdtControl(window,window->visRgn);
  383.     
  384.     return BaseUpdateWindow(window,infoPtr,data);
  385. }
  386.  
  387.  
  388. /* handle window resize for draw window */
  389.  
  390. void *DrawResizeWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  391. {    
  392.     #pragma unused (infoPtr)
  393.     Rect *oldSize,gbRect;
  394.     
  395.     oldSize = (Rect *)data;
  396.     gbRect = *oldSize;
  397.     gbRect.top = gbRect.bottom - kGrowBoxWidth;
  398.     gbRect.left = gbRect.right - kGrowBoxWidth;
  399.     EraseRect(&gbRect);
  400.  
  401.     MoveScrollBars(window);
  402.     
  403.     gbRect = window->portRect;
  404.     gbRect.top = gbRect.bottom - kGrowBoxWidth;
  405.     gbRect.left = gbRect.right - kGrowBoxWidth;
  406.     ValidRect(&gbRect);
  407.     MyDrawGrowIcon(window);
  408.  
  409.     return nil;
  410. }
  411.  
  412.  
  413. /* handle print for draw window */
  414.  
  415. void *DrawPrintWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  416. {
  417.     #pragma unused (window,data)
  418.     Boolean shouldContinue;
  419.     TPPrPort thePrPort;
  420.     TPrStatus theStatus;
  421.     Point zeroOffset = {0,0};
  422.     
  423.     // open print driver
  424.     
  425.     PrOpen();
  426.     if (PrError()!=noErr) {
  427.         DoError(PrError());
  428.         return nil;
  429.     }
  430.     
  431.     // display print dialog
  432.     
  433.     SetCursor(&qd.arrow);
  434.     shouldContinue = PrJobDialog(infoPtr->printRecord);
  435.     if (PrError()!=noErr) {
  436.         DoError(PrError());
  437.         return nil;
  438.     }
  439.     if (!shouldContinue)
  440.         return nil;
  441.     
  442.     // init printing grafport
  443.     
  444.     thePrPort = PrOpenDoc(infoPtr->printRecord,nil,nil);
  445.     if (PrError()==noErr) {
  446.         PrOpenPage(thePrPort,nil);
  447.         if (PrError()==noErr)
  448.             DrawAllShapes(infoPtr,zeroOffset);
  449.         PrClosePage(thePrPort);
  450.     }
  451.     PrCloseDoc(thePrPort);
  452.     
  453.     if ((((TPPrint)*(infoPtr->printRecord))->prJob.bJDocLoop==bSpoolLoop) && (PrError() == noErr))
  454.         PrPicFile(infoPtr->printRecord, nil, nil, nil, &theStatus);                
  455.  
  456.     // close print driver
  457.     
  458.     PrClose();
  459.     
  460.     return nil;
  461. }
  462.  
  463.  
  464. /* handle page setup for draw window */
  465.  
  466. void *DrawPageSetupWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  467. {
  468.     Boolean changed;
  469.     
  470.     changed = CheckPageSize(window,infoPtr);
  471.     if (!changed)
  472.         ReCalcScrollBars(window,infoPtr);
  473.  
  474.     return BasePageSetupWindow(window,infoPtr,data);
  475. }
  476.  
  477.  
  478. /* handle save for draw window */
  479.  
  480. void *DrawSaveWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  481. {
  482.     OSErr err;
  483.     SMPSaveType saveHow;
  484.     short fRefNum,resRefNum;
  485.     
  486.     saveHow = (SMPSaveType)data;
  487.     
  488.     // handle save as
  489.     
  490.     if (saveHow==kSMPSaveAs) {
  491.     
  492.         // create the new file, deleting any existing file, as per user's std file request
  493.         
  494.         err = FSpCreate(&infoPtr->fileSpec,kAppCreator,kDrawingType,smRoman);
  495.         if (err==dupFNErr) {
  496.             FSpDelete(&infoPtr->fileSpec);
  497.             err = FSpCreate(&infoPtr->fileSpec,kAppCreator,kDrawingType,smRoman);
  498.         }
  499.         if (err!=noErr) {
  500.             DoError(err);
  501.             return nil;
  502.         }
  503.         FSpCreateResFile(&infoPtr->fileSpec,kAppCreator,kDrawingType,smRoman);
  504.         err = ResError();
  505.         if (err!=noErr) {
  506.             FSpDelete(&infoPtr->fileSpec);
  507.             DoError(err);
  508.             return nil;
  509.         }
  510.             
  511.         // open the new file (data fork)
  512.         
  513.         err = FSpOpenDF(&infoPtr->fileSpec,fsRdWrPerm,&fRefNum);
  514.         if (err!=noErr) {
  515.             FSpDelete(&infoPtr->fileSpec);
  516.             DoError(err);
  517.             return nil;
  518.         }
  519.         
  520.         // open the new file (resource fork)
  521.         
  522.         resRefNum = FSpOpenResFile(&infoPtr->fileSpec,fsRdWrPerm);
  523.         err = ResError();
  524.         if (err!=noErr) {
  525.             FSClose(fRefNum);
  526.             FSpDelete(&infoPtr->fileSpec);
  527.             DoError(err);
  528.             return nil;
  529.         }
  530.         
  531.         // close the old file, if it exists
  532.         
  533.         if (infoPtr->fRefNum)
  534.             FSClose(infoPtr->fRefNum);
  535.             
  536.         // store the new fRefNum into the document data structure
  537.         
  538.         infoPtr->fRefNum = fRefNum;
  539.     }
  540.     else
  541.         resRefNum = infoPtr->resRefNum;
  542.     
  543.     // add digital signature information
  544.     
  545.     DSIGSaveFile(infoPtr,resRefNum,false);
  546.     if (saveHow==kSMPSaveAs) {
  547.         if (infoPtr->resRefNum)
  548.             CloseResFile(infoPtr->resRefNum);
  549.         infoPtr->resRefNum = resRefNum;
  550.     }
  551.     
  552.     // save the actual file
  553.     
  554.     err = SaveDrawingToDisk(infoPtr->fRefNum,infoPtr);
  555.     if (err!=noErr) {
  556.         DoError(err);
  557.         return nil;
  558.     }
  559.     
  560.     SetWTitle(window,infoPtr->fileSpec.name);    
  561.     return BaseSaveWindow(window,infoPtr,data);
  562. }
  563.  
  564.  
  565. /* handle load for draw window */
  566.  
  567. void *DrawLoadWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  568. {
  569.     OSErr err;
  570.     long count;
  571.     short fRefNum,resRefNum;
  572.     FSSpec *fSpec;
  573.     char hState;
  574.     
  575.     fSpec = data;
  576.     
  577.     // open the file.  we leave it open for reading and writing the whole time
  578.     // that we need to read stuff out of it.
  579.     
  580.     err = FSpOpenDF(fSpec,fsRdWrPerm,&fRefNum);    // we leave the file open
  581.     if (err!=noErr) {
  582.         DoError(err);
  583.         return nil;
  584.     }
  585.     infoPtr->fRefNum = fRefNum;
  586.     resRefNum = FSpOpenResFile(fSpec,fsRdWrPerm);
  587.     err = ResError();
  588.     if (err!=noErr) {
  589.         FSClose(fRefNum);
  590.         DoError(err);
  591.         return nil;
  592.     }
  593.     infoPtr->resRefNum = resRefNum;
  594.  
  595.     // read print record
  596.     
  597.     count = sizeof(TPrint);
  598.     hState = HGetState((Handle)infoPtr->printRecord);
  599.     HLock((Handle)infoPtr->printRecord);
  600.     err = FSRead(fRefNum,&count,*(infoPtr->printRecord));
  601.     HSetState((Handle)infoPtr->printRecord,hState);
  602.     if (err!=noErr) {
  603.         DoError(err);
  604.         return nil;
  605.     }
  606.     
  607.     // read shape information
  608.     
  609.     LoadShapesFromDisk(fRefNum,(ShapeListPtr *)&infoPtr->data);
  610.     
  611.     // do digital signature stuff
  612.     
  613.     DSIGOpenFile(infoPtr);
  614.     
  615.     BaseLoadWindow(window,infoPtr,data);
  616. }
  617.  
  618.  
  619. /* handle control hit (in scroll bars) for draw window */
  620.  
  621. void *DrawHitControlWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  622. {
  623.     ControlHitMessage *msg;
  624.     short newValue,oldValue;
  625.     Point mousePos;
  626.     
  627.     msg = (ControlHitMessage *)data;
  628.     mousePos = msg->ev->where;
  629.     GlobalToLocal(&mousePos);
  630.     
  631.     switch (msg->part) {
  632.         case inPageUp:
  633.         case inPageDown:
  634.             TrackControl(msg->control,mousePos,(ProcPtr)ScrollActionProc);
  635.             break;
  636.         case inUpButton:
  637.         case inDownButton:
  638.             TrackControl(msg->control,mousePos,(ProcPtr)ScrollActionProc);
  639.             break;
  640.         case inThumb:
  641.             oldValue = GetCtlValue(msg->control);
  642.             if (TrackControl(msg->control,mousePos,nil)) {
  643.                 newValue = GetCtlValue(msg->control);
  644.                 if (oldValue!=newValue) {
  645.                     if (msg->control==(ControlHandle)VSCROLL)
  646.                         MoveGraphics(window,infoPtr,0,newValue-oldValue);
  647.                     else
  648.                         MoveGraphics(window,infoPtr,newValue-oldValue,0);
  649.                 }
  650.             }
  651.             break;
  652.     }
  653.         
  654.     return nil;
  655. }
  656.  
  657.  
  658. /* handle select all for draw window */
  659.  
  660. void *DrawSelectAllWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  661. {
  662.     #pragma unused (data)
  663.     ShapeListPtr shapeList;
  664.     
  665.     for (shapeList=infoPtr->data; shapeList!=nil; shapeList=shapeList->next) {
  666.         shapeList->selected = true;
  667.         InvalShapeArea(window,infoPtr,shapeList);
  668.     }
  669.     
  670.     FixDrawMenus(infoPtr);
  671.     return nil;
  672. }
  673.  
  674.  
  675. /* handle group shapes for draw window */
  676.  
  677. void *DrawGroupWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  678. {
  679.     ShapeListPtr shapeList,prevShape,selectedShape;
  680.     ShapeListPtr groupList;
  681.     Point anchor,destination,emptyPt = {0,0};
  682.     
  683.     // put all selected shapes into groupList, pulling them out of shapeList
  684.     
  685.     groupList = nil;
  686.     shapeList = infoPtr->data;
  687.     prevShape = nil;        
  688.     while (shapeList!=nil) {
  689.         if (shapeList->selected) {
  690.             selectedShape = shapeList;
  691.             selectedShape->selected = false;
  692.             if (prevShape)
  693.                 prevShape->next = selectedShape->next;
  694.             else
  695.                 infoPtr->data = shapeList->next;
  696.             shapeList = shapeList->next;
  697.             selectedShape->next = groupList;
  698.             groupList = selectedShape;
  699.     
  700.         }
  701.         else {
  702.             prevShape = shapeList;
  703.             shapeList = shapeList->next;
  704.         }
  705.     }
  706.     
  707.     GetGroupBounds(groupList,&anchor,&destination);
  708.     shapeList = AddShape(kBeginGroupTag,anchor,destination,groupList,
  709.                         (ShapeListPtr *)&infoPtr->data,false);
  710.     shapeList->selected = true;
  711.     InvalShapeArea(window,infoPtr,shapeList);
  712.     ClearAppUndo();
  713.     FixDrawMenus(infoPtr);
  714.     
  715.     return BaseGroupWindow(window,infoPtr,data);
  716. }
  717.  
  718.  
  719. /* handle ungroup shapes for draw window */
  720.  
  721. void *DrawUnGroupWindow(WindowPtr window,WInfoPtr infoPtr,void *data)
  722. {
  723.     ShapeListPtr shapeList,prevShape,selectedShape;
  724.     ShapeListPtr ungroupShapes;
  725.     
  726.     // put all group shapes into ungroupShapes, pulling them out of shapeList
  727.     
  728.     ungroupShapes = nil;
  729.     shapeList = infoPtr->data;
  730.     prevShape = nil;        
  731.     while (shapeList!=nil) {
  732.         if (shapeList->selected && shapeList->shapeType==kBeginGroupTag) {
  733.             selectedShape = shapeList;
  734.             selectedShape->selected = false;
  735.             if (prevShape)
  736.                 prevShape->next = selectedShape->next;
  737.             else
  738.                 infoPtr->data = shapeList->next;
  739.             shapeList = shapeList->next;
  740.             selectedShape->next = ungroupShapes;
  741.             ungroupShapes = selectedShape;
  742.     
  743.         }
  744.         else {
  745.             prevShape = shapeList;
  746.             shapeList = shapeList->next;
  747.         }
  748.     }
  749.     
  750.     // add all of the sub-group shapes into the shape list
  751.     
  752.     while (ungroupShapes!=nil) {
  753.         InvalShapeArea(window,infoPtr,ungroupShapes);
  754.         
  755.         shapeList = ungroupShapes->subList;
  756.         while (shapeList!=nil) {
  757.             selectedShape = shapeList;
  758.             selectedShape->selected = true;
  759.             shapeList = shapeList->next;
  760.             selectedShape->next = infoPtr->data;
  761.             infoPtr->data = selectedShape;
  762.         }
  763.         
  764.         shapeList = ungroupShapes;
  765.         if (shapeList->isSigned) {
  766.             shapeList->digSig->shouldDelete = true;    // invalidate the group obj digital signature
  767.             shapeList->digSig->shape = nil;
  768.         }
  769.         ungroupShapes = ungroupShapes->next;
  770.         DisposPtrChk(shapeList);
  771.     }
  772.     ClearAppUndo();
  773.     FixDrawMenus(infoPtr);
  774.             
  775.     return BaseUnGroupWindow(window,infoPtr,data);
  776. }
  777.  
  778.  
  779. /*------- non window-class stuff ---------*/
  780.  
  781.  
  782. /* let the user enter a new shape */
  783.  
  784. void EnterNewShape(WindowPtr window,WInfoPtr infoPtr,Point where)
  785. {
  786.     Point anchor,destination,offsetPos;
  787.     Point emptyPt = {0,0};
  788.     Point *scrollPos;
  789.     ShapeListPtr shapeList;
  790.     
  791.     scrollPos = (Point *)&infoPtr->otherData[kViewOffset];
  792.     anchor = where;
  793.     GlobalToLocal(&anchor);
  794.     destination = anchor;
  795.     
  796.     RubberBandShape(gCurrentShape,anchor,&destination,emptyPt);
  797.     DrawCurrentShape(gCurrentShape,anchor,destination,emptyPt);
  798.  
  799.     offsetPos.h = scrollPos->h-infoPtr->leftIndent;
  800.     offsetPos.v = scrollPos->v-infoPtr->topIndent;
  801.     
  802.     anchor.h += offsetPos.h;
  803.     anchor.v += offsetPos.v;
  804.     destination.h += offsetPos.h;
  805.     destination.v += offsetPos.v;
  806.  
  807.     for (shapeList = infoPtr->data; shapeList!=nil; shapeList = shapeList->next) {
  808.         if (shapeList->selected) {
  809.             shapeList->selected = false;
  810.             EraseAnchorPoints(shapeList,offsetPos);
  811.         }
  812.     }
  813.  
  814.     AddShape(gCurrentShape,anchor,destination,nil,
  815.                 (ShapeListPtr *)&infoPtr->data,false);
  816.     AddShapeUndo(gCurrentShape,anchor,destination,window,infoPtr);    
  817. }
  818.  
  819.  
  820. /* do the rubber band thing with either a new or existing shape */
  821.  
  822. void RubberBandShape(short shapeType,Point anchor,Point *retDestination,Point offset)
  823. {
  824.     RgnHandle prevRgn,newRgn,invRgn,opDiffRgn,swapRgn,innerRgn;
  825.     Point destination,newDest;
  826.     
  827.     destination = *retDestination;
  828.     
  829.     PenNormal();
  830.     switch (shapeType) {
  831.         case kLineShape:
  832.             PenMode(patXor);
  833.             DrawCurrentShape(shapeType,anchor,destination,offset);
  834.             while (WaitMouseUp()) {
  835.                 GetMouse(&newDest);
  836.                 newDest.h -= offset.h;
  837.                 newDest.v -= offset.v;
  838.                 if (!EqualPt(newDest,destination)) {
  839.                     DrawCurrentShape(shapeType,anchor,destination,offset);
  840.                     destination = newDest;
  841.                     DrawCurrentShape(shapeType,anchor,destination,offset);
  842.                 }
  843.             }
  844.             break;
  845.         default:
  846.             prevRgn = NewRgn();
  847.             newRgn = NewRgn();
  848.             invRgn = NewRgn();
  849.             opDiffRgn = NewRgn();
  850.             innerRgn = NewRgn();
  851.             
  852.             OpenRgn();
  853.             DrawCurrentShape(shapeType,anchor,destination,offset);
  854.             CloseRgn(prevRgn);
  855.             CopyRgn(prevRgn,innerRgn);
  856.             InsetRgn(innerRgn,1,1);
  857.             DiffRgn(prevRgn,innerRgn,prevRgn);
  858.             
  859.             InvertRgn(prevRgn);
  860.             EmptyRgn(newRgn);
  861.             
  862.             while (WaitMouseUp()) {
  863.                 GetMouse(&newDest);
  864.                 newDest.h -= offset.h;
  865.                 newDest.v -= offset.v;
  866.                 if (!EqualPt(newDest,destination)) {
  867.                     destination = newDest;
  868.                     
  869.                     OpenRgn();
  870.                     DrawCurrentShape(shapeType,anchor,destination,offset);
  871.                     CloseRgn(newRgn);
  872.                     CopyRgn(newRgn,innerRgn);
  873.                     InsetRgn(innerRgn,1,1);
  874.                     DiffRgn(newRgn,innerRgn,newRgn);
  875.                     
  876.                     DiffRgn(prevRgn,newRgn,invRgn);
  877.                     DiffRgn(newRgn,prevRgn,opDiffRgn);
  878.                     UnionRgn(invRgn,opDiffRgn,invRgn);
  879.                     InvertRgn(invRgn);
  880.                     swapRgn = prevRgn;
  881.                     prevRgn = newRgn;
  882.                     newRgn = swapRgn;
  883.                 }
  884.             }
  885.             InvertRgn(prevRgn);
  886.             DisposeRgn(prevRgn);
  887.             DisposeRgn(newRgn);
  888.             DisposeRgn(invRgn);
  889.             DisposeRgn(opDiffRgn);
  890.             DisposeRgn(innerRgn);
  891.             break;
  892.     }
  893.     
  894.     PenNormal();
  895.     *retDestination = destination;
  896. }
  897.     
  898.  
  899. /* select or move or stretch a shape that already exists */
  900. /* return true if a shape changed */
  901.  
  902. Boolean WarpExistingShape(WindowPtr window,WInfoPtr infoPtr,Point where,Boolean extendSelection)
  903. {
  904.     Point *scrollPos,offsetPos;
  905.     ShapeListPtr shapeList,otherList;
  906.     Boolean hitShape,wasSelected,warpedShape,changedShape;
  907.     Point newDest,oldDest,firstDest;
  908.     
  909.     warpedShape = false;
  910.     hitShape = false;
  911.     wasSelected = false;
  912.     changedShape = false;
  913.     
  914.     // determine offsets due to scrolling, indent, global-local changes
  915.     
  916.     scrollPos = (Point *)&infoPtr->otherData[kViewOffset];
  917.     offsetPos.h = infoPtr->leftIndent - scrollPos->h;
  918.     offsetPos.v = infoPtr->topIndent - scrollPos->v;
  919.     GlobalToLocal(&where);
  920.  
  921.     // do hit testing
  922.     
  923.     shapeList = infoPtr->data;
  924.     while (shapeList && !hitShape) {
  925.         hitShape = CheckHitShape(window,infoPtr,offsetPos,where,shapeList,&warpedShape);
  926.         if (!hitShape)
  927.             shapeList = shapeList->next;
  928.         if (warpedShape)
  929.             changedShape = true;
  930.     }
  931.     
  932.     
  933.     // mark shape selected
  934.  
  935.     if (hitShape) {
  936.         
  937.         if (shapeList->selected==false) {
  938.             wasSelected = false;
  939.             shapeList->selected = true;
  940.         }
  941.         else
  942.             wasSelected = true;
  943.     }
  944.         
  945.     // if shift wasn't held, unselect all other objects
  946.     
  947.     if ((extendSelection==false) && ((warpedShape==true)||(hitShape==false)||(wasSelected==false))) {
  948.         for (otherList = infoPtr->data; otherList!=nil; otherList = otherList->next) {
  949.             if (otherList->selected && (!hitShape||(otherList!=shapeList)||!shapeList->selected)) {
  950.                 otherList->selected = false;
  951.                 EraseAnchorPoints(otherList,offsetPos);
  952.             }
  953.         }
  954.     }
  955.  
  956.     if (hitShape) {
  957.     
  958.         for (otherList = infoPtr->data; otherList!=nil; otherList = otherList->next) {
  959.             if (otherList->selected) {
  960.                 InvalShapeArea(window,infoPtr,otherList);
  961.             }
  962.         }
  963.         
  964.         // do shape moving stuff
  965.         
  966.         GetMouse(&oldDest);
  967.         newDest = oldDest;
  968.         while (WaitMouseUp() && EqualPt(newDest,oldDest))
  969.             GetMouse(&newDest);
  970.         if (!EqualPt(newDest,oldDest)) {
  971.         
  972.             // draw shape in gray, since we're going to move it
  973.             
  974.             for (otherList = infoPtr->data; otherList!=nil; otherList = otherList->next) {
  975.                 if (otherList->selected) {
  976.                     #ifdef dangerousPattern
  977.                     PenPat(qd.gray);
  978.                     #else
  979.                     PenPat(&qd.gray);
  980.                     #endif
  981.                     DrawShapeObject(otherList,offsetPos,false);
  982.                     #ifdef dangerousPattern
  983.                     PenPat(qd.black);
  984.                     #else
  985.                     PenPat(&qd.black);
  986.                     #endif
  987.                     PenMode(patXor);
  988.                     DrawShapeObject(otherList,offsetPos,false);
  989.                 }
  990.             }
  991.             
  992.             // move shape(s) here
  993.  
  994.             GetMouse(&firstDest);
  995.             newDest = firstDest;
  996.             while (WaitMouseUp()) {
  997.                 oldDest = newDest;
  998.                 GetMouse(&newDest);
  999.                 if (!EqualPt(oldDest,newDest)) {
  1000.                     oldDest.h = offsetPos.h - firstDest.h + oldDest.h;
  1001.                     oldDest.v = offsetPos.v - firstDest.v + oldDest.v;
  1002.                     for (otherList = infoPtr->data; otherList!=nil; otherList = otherList->next) {
  1003.                         if (otherList->selected)
  1004.                             DrawShapeObject(otherList,oldDest,false);
  1005.                     }
  1006.                     oldDest.h = offsetPos.h - firstDest.h + newDest.h;
  1007.                     oldDest.v = offsetPos.v - firstDest.v + newDest.v;
  1008.                     for (otherList = infoPtr->data; otherList!=nil; otherList = otherList->next) {
  1009.                         if (otherList->selected)
  1010.                             DrawShapeObject(otherList,oldDest,false);
  1011.                     }
  1012.                 }
  1013.             }
  1014.             for (otherList = infoPtr->data; otherList!=nil; otherList = otherList->next) {
  1015.                 if (otherList->selected) {
  1016.                     OffsetShape(otherList,newDest.h-firstDest.h,newDest.v-firstDest.v);
  1017.                     InvalShapeArea(window,infoPtr,otherList);
  1018.                 }
  1019.             }        
  1020.             changedShape = true;
  1021.  
  1022.         }
  1023.     }
  1024.     
  1025.     PenNormal();
  1026.     return changedShape;
  1027. }
  1028.  
  1029.  
  1030. /* perform a hit test on the object, returning whether the object was hit or should be warped */
  1031.  
  1032. Boolean CheckHitShape(WindowPtr window,WInfoPtr infoPtr,Point offsetPos,Point hitPt,
  1033.                         ShapeListPtr theShape,Boolean *warp)
  1034. {
  1035.     RgnHandle shape,overShape;
  1036.     Rect boundBox;
  1037.     Boolean hitShape;
  1038.     Point anchor,destination;
  1039.     float slope,intercept,hitPoint;
  1040.     ShapeListPtr groupList;
  1041.     
  1042.     hitShape = false;
  1043.     *warp = false;
  1044.     shape = NewRgn();
  1045.     overShape = NewRgn();
  1046.         
  1047.     // check bounding box
  1048.     
  1049.     if (theShape->anchor.h < theShape->destination.h) {
  1050.         boundBox.left = theShape->anchor.h;
  1051.         boundBox.right = theShape->destination.h;
  1052.     }
  1053.     else {
  1054.         boundBox.left = theShape->destination.h;
  1055.         boundBox.right = theShape->anchor.h;
  1056.     }
  1057.     if (theShape->anchor.v < theShape->destination.v) {
  1058.         boundBox.top = theShape->anchor.v;
  1059.         boundBox.bottom = theShape->destination.v;
  1060.     }
  1061.     else {
  1062.         boundBox.top = theShape->destination.v;
  1063.         boundBox.bottom = theShape->anchor.v;
  1064.     }
  1065.     boundBox.top += offsetPos.v;
  1066.     boundBox.bottom += offsetPos.v;
  1067.     boundBox.left += offsetPos.h;
  1068.     boundBox.right += offsetPos.h;    
  1069.     InsetRect(&boundBox,-kSlop,-kSlop);
  1070.  
  1071.     // check hit in digital signature button
  1072.     
  1073.     if (DSIGHitShape(infoPtr,hitPt,offsetPos,theShape))
  1074.         hitShape = false;
  1075.             
  1076.     // check hit in shape area
  1077.     
  1078.     else if (PtInRect(hitPt,&boundBox)) {
  1079.         
  1080.         // check hit on group shape
  1081.                 
  1082.         if (theShape->shapeType==kBeginGroupTag) {
  1083.             if (CheckHitAnchor(theShape,hitPt,offsetPos,&anchor,&destination))
  1084.                 hitShape = true;
  1085.             else
  1086.                 for (groupList=theShape->subList; groupList!=nil && hitShape==false;
  1087.                         groupList=groupList->next) {
  1088.                     if (CheckHitShape(window,infoPtr,offsetPos,hitPt,groupList,warp))
  1089.                         hitShape = true;
  1090.                 }
  1091.         }
  1092.         
  1093.         // check rubber banding (for warping an object)
  1094.  
  1095.         else if (CheckHitAnchor(theShape,hitPt,offsetPos,&anchor,&destination)) {
  1096.             #ifdef dangerousPattern
  1097.             PenPat(qd.gray);
  1098.             #else
  1099.             PenPat(&qd.gray);
  1100.             #endif
  1101.             DrawShapeObject(theShape,offsetPos,false);
  1102.             #ifdef dangerousPattern
  1103.             PenPat(qd.black);
  1104.             #else
  1105.             PenPat(&qd.black);
  1106.             #endif
  1107.             InvalShapeArea(window,infoPtr,theShape);
  1108.             RubberBandShape(theShape->shapeType,anchor,&destination,offsetPos);
  1109.             theShape->anchor = anchor;
  1110.             theShape->destination = destination;
  1111.             InvalShapeArea(window,infoPtr,theShape);
  1112.             hitShape = true;
  1113.             *warp = true;
  1114.         }
  1115.         
  1116.         // check hit on an object -- line
  1117.  
  1118.         else if (theShape->shapeType==kLineShape) {
  1119.             hitPt.h -= offsetPos.h;
  1120.             hitPt.v -= offsetPos.v;
  1121.             if (theShape->anchor.h==theShape->destination.h) {
  1122.                 if ((theShape->anchor.h > hitPt.h-kLineSlop) &&
  1123.                     (theShape->anchor.h < hitPt.h+kLineSlop))
  1124.                     hitShape = true;
  1125.             }
  1126.             else {
  1127.                 slope = (float)(theShape->anchor.v-theShape->destination.v) /
  1128.                         (float)(theShape->anchor.h-theShape->destination.h);
  1129.                 intercept = (float)theShape->anchor.v - (slope * (float)theShape->anchor.h);
  1130.                 hitPoint = (slope * (float)hitPt.h) + intercept;
  1131.                 if (((short)hitPoint > (hitPt.v-kLineSlop)) &&
  1132.                         ((short)hitPoint < (hitPt.v+kLineSlop)))
  1133.                     hitShape = true;
  1134.                 else {
  1135.                     hitPoint = ((float)hitPt.v - intercept) / slope;
  1136.                     if (((short)hitPoint > (hitPt.h-kLineSlop)) &&
  1137.                             ((short)hitPoint < (hitPt.h+kLineSlop)))
  1138.                         hitShape = true;
  1139.                 }
  1140.             }
  1141.         }
  1142.         
  1143.         // check hit on an object -- other
  1144.  
  1145.         else {
  1146.             OpenRgn();
  1147.             DrawShapeObject(theShape,offsetPos,false);
  1148.             CloseRgn(shape);
  1149.             CopyRgn(shape,overShape);
  1150.             InsetRgn(shape,kSlop,kSlop);
  1151.             InsetRgn(overShape,-kSlop,-kSlop);
  1152.             DiffRgn(overShape,shape,overShape);
  1153.             if (PtInRgn(hitPt,overShape))
  1154.                 hitShape = true;
  1155.         }
  1156.     }
  1157.  
  1158.     DisposeRgn(shape);
  1159.     DisposeRgn(overShape);
  1160.     return hitShape;
  1161. }
  1162.  
  1163.  
  1164. /* draws all the shapes */
  1165.  
  1166. void DrawAllShapes(WInfoPtr infoPtr,Point offsetPos)
  1167. {
  1168.     ShapeListPtr shapeList;
  1169.  
  1170.     PenNormal();
  1171.     for (shapeList=infoPtr->data; shapeList!=nil; shapeList=shapeList->next) {
  1172.         DrawShapeObject(shapeList,offsetPos,true);
  1173.     }
  1174. }
  1175.  
  1176.  
  1177. /* draws the shape from a shape record */
  1178.  
  1179. void DrawShapeObject(ShapeListPtr theShape,Point drawOffset,Boolean selected)
  1180. {
  1181.     if (theShape->shapeType==kBeginGroupTag) {
  1182.         DrawAnchorPoints(theShape,drawOffset,selected ? theShape->selected : false);
  1183.         if (selected)
  1184.             DSIGDrawSigner(theShape,drawOffset);
  1185.         for (theShape = theShape->subList; theShape!=nil; theShape = theShape->next)
  1186.             DrawShapeObject(theShape,drawOffset,false);
  1187.     }
  1188.     else {
  1189.         DrawCurrentShape(theShape->shapeType,theShape->anchor,theShape->destination,drawOffset);
  1190.         DrawAnchorPoints(theShape,drawOffset,selected ? theShape->selected : false);
  1191.         if (selected)
  1192.             DSIGDrawSigner(theShape,drawOffset);
  1193.     }
  1194. }
  1195.  
  1196.  
  1197. /* draws the shape from components*/
  1198.  
  1199. void DrawCurrentShape(short theShape,Point anchor,Point endPt,Point drawOffset)
  1200. {
  1201.     Rect theRect;
  1202.     Point emptyPt = {0,0};
  1203.     
  1204.     anchor.h += drawOffset.h;
  1205.     anchor.v += drawOffset.v;
  1206.     endPt.h += drawOffset.h;
  1207.     endPt.v += drawOffset.v;
  1208.     
  1209.     // draw the shape
  1210.     
  1211.     switch (theShape) {
  1212.         case kLineShape:
  1213.             MoveTo(anchor.h,anchor.v);
  1214.             LineTo(endPt.h,endPt.v);
  1215.             break;
  1216.         case kRectShape:
  1217.             SetRect(&theRect,anchor.h,anchor.v,endPt.h,endPt.v);
  1218.             FixRect(&theRect);
  1219.             FrameRect(&theRect);
  1220.             break;
  1221.         case kRoundRectShape:
  1222.             SetRect(&theRect,anchor.h,anchor.v,endPt.h,endPt.v);
  1223.             FixRect(&theRect);
  1224.             FrameRoundRect(&theRect,15,15);
  1225.             break;
  1226.         case kOvalShape:
  1227.             SetRect(&theRect,anchor.h,anchor.v,endPt.h,endPt.v);
  1228.             FixRect(&theRect);
  1229.             FrameOval(&theRect);
  1230.             break;
  1231.     }    
  1232. }
  1233.  
  1234. /* draw the anchor points for a shape */
  1235.  
  1236. void DrawAnchorPoints(ShapeListPtr theShape,Point drawOffset,Boolean selected)
  1237. {
  1238.     Rect theRect;
  1239.     Boolean fourAnchors;
  1240.     Point anchor,endPt;
  1241.     
  1242.     anchor = theShape->anchor;
  1243.     endPt = theShape->destination;
  1244.     
  1245.     if (theShape->shapeType==kLineShape)
  1246.         fourAnchors = false;
  1247.     else
  1248.         fourAnchors = true;
  1249.         
  1250.     anchor.h += drawOffset.h;
  1251.     anchor.v += drawOffset.v;
  1252.     endPt.h += drawOffset.h;
  1253.     endPt.v += drawOffset.v;
  1254.  
  1255.     SetRect(&theRect,anchor.h-kAnchorWidth,anchor.v-kAnchorWidth,
  1256.             anchor.h+kAnchorWidth,anchor.v+kAnchorWidth);
  1257.     if (selected)
  1258.         #ifdef dangerousPattern
  1259.         FillRect(&theRect,qd.black);
  1260.         #else
  1261.         FillRect(&theRect,&qd.black);
  1262.         #endif
  1263.     SetRect(&theRect,endPt.h-kAnchorWidth,endPt.v-kAnchorWidth,
  1264.             endPt.h+kAnchorWidth,endPt.v+kAnchorWidth);
  1265.     if (selected)
  1266.         #ifdef dangerousPattern
  1267.         FillRect(&theRect,qd.black);
  1268.         #else
  1269.         FillRect(&theRect,&qd.black);
  1270.         #endif
  1271.     if (fourAnchors) {
  1272.         SetRect(&theRect,anchor.h-kAnchorWidth,endPt.v-kAnchorWidth,
  1273.                 anchor.h+kAnchorWidth,endPt.v+kAnchorWidth);
  1274.         if (selected)
  1275.             #ifdef dangerousPattern
  1276.             FillRect(&theRect,qd.black);
  1277.             #else
  1278.             FillRect(&theRect,&qd.black);
  1279.             #endif
  1280.         SetRect(&theRect,endPt.h-kAnchorWidth,anchor.v-kAnchorWidth,
  1281.                 endPt.h+kAnchorWidth,anchor.v+kAnchorWidth);
  1282.         if (selected)
  1283.             #ifdef dangerousPattern
  1284.             FillRect(&theRect,qd.black);
  1285.             #else
  1286.             FillRect(&theRect,&qd.black);
  1287.             #endif
  1288.     }
  1289. }
  1290.  
  1291.  
  1292. /* erase the anchor points for a shape */
  1293.  
  1294. void EraseAnchorPoints(ShapeListPtr theShape,Point drawOffset)
  1295. {
  1296.     Point anchor,endPt;
  1297.     Rect theRect;
  1298.     Boolean fourAnchors;
  1299.     
  1300.     if (theShape->shapeType == kLineShape)
  1301.         fourAnchors = false;
  1302.     else
  1303.         fourAnchors = true;
  1304.         
  1305.     anchor.h = theShape->anchor.h + drawOffset.h;
  1306.     anchor.v = theShape->anchor.v + drawOffset.v;
  1307.     endPt.h = theShape->destination.h + drawOffset.h;
  1308.     endPt.v = theShape->destination.v + drawOffset.v;
  1309.  
  1310.     SetRect(&theRect,anchor.h-kAnchorWidth,anchor.v-kAnchorWidth,
  1311.             anchor.h+kAnchorWidth,anchor.v+kAnchorWidth);
  1312.     InvalRect(&theRect);
  1313.     SetRect(&theRect,endPt.h-kAnchorWidth,endPt.v-kAnchorWidth,
  1314.             endPt.h+kAnchorWidth,endPt.v+kAnchorWidth);
  1315.     InvalRect(&theRect);
  1316.     if (fourAnchors) {
  1317.         SetRect(&theRect,anchor.h-kAnchorWidth,endPt.v-kAnchorWidth,
  1318.                 anchor.h+kAnchorWidth,endPt.v+kAnchorWidth);
  1319.         InvalRect(&theRect);
  1320.         SetRect(&theRect,endPt.h-kAnchorWidth,anchor.v-kAnchorWidth,
  1321.                 endPt.h+kAnchorWidth,anchor.v+kAnchorWidth);
  1322.         InvalRect(&theRect);
  1323.     }
  1324. }
  1325.  
  1326.  
  1327. /* see if we hit an anchor point, and if yes, return anchor and destination points */
  1328.  
  1329. Boolean CheckHitAnchor(ShapeListPtr theShape,Point hitPt,Point offsetPos,Point *anchor,
  1330.                         Point *endPt)
  1331. {
  1332.     Rect theRect;
  1333.     Boolean fourAnchors;
  1334.     
  1335.     hitPt.h -= offsetPos.h;
  1336.     hitPt.v -= offsetPos.v;
  1337.     
  1338.     if (theShape->selected==false)
  1339.         return false;
  1340.         
  1341.     if (theShape->shapeType == kLineShape)
  1342.         fourAnchors = false;
  1343.     else
  1344.         fourAnchors = true;
  1345.         
  1346.     *anchor = theShape->anchor;
  1347.     *endPt = theShape->destination;
  1348.  
  1349.     SetRect(&theRect,anchor->h-kAnchorWidth,anchor->v-kAnchorWidth,
  1350.             anchor->h+kAnchorWidth,anchor->v+kAnchorWidth);
  1351.     if (PtInRect(hitPt,&theRect)) {
  1352.         *anchor = theShape->destination;
  1353.         *endPt = theShape->anchor;
  1354.         return true;
  1355.     }
  1356.     
  1357.     SetRect(&theRect,endPt->h-kAnchorWidth,endPt->v-kAnchorWidth,
  1358.             endPt->h+kAnchorWidth,endPt->v+kAnchorWidth);
  1359.     if (PtInRect(hitPt,&theRect)) {
  1360.         *anchor = theShape->anchor;
  1361.         *endPt = theShape->destination;
  1362.         return true;
  1363.     }
  1364.  
  1365.     if (fourAnchors) {
  1366.     
  1367.         SetRect(&theRect,anchor->h-kAnchorWidth,endPt->v-kAnchorWidth,
  1368.                 anchor->h+kAnchorWidth,endPt->v+kAnchorWidth);
  1369.         if (PtInRect(hitPt,&theRect)) {
  1370.             anchor->h = theShape->destination.h;
  1371.             anchor->v = theShape->anchor.v;
  1372.             endPt->h = theShape->anchor.h;
  1373.             endPt->v = theShape->destination.v;
  1374.             return true;
  1375.         }
  1376.  
  1377.         SetRect(&theRect,endPt->h-kAnchorWidth,anchor->v-kAnchorWidth,
  1378.                 endPt->h+kAnchorWidth,anchor->v+kAnchorWidth);
  1379.         if (PtInRect(hitPt,&theRect)) {
  1380.             anchor->h = theShape->anchor.h;
  1381.             anchor->v = theShape->destination.v;
  1382.             endPt->h = theShape->destination.h;
  1383.             endPt->v = theShape->anchor.v;
  1384.             return true;
  1385.         }
  1386.     }
  1387.     return false;
  1388. }
  1389.  
  1390.  
  1391. /* re-orient rectangle so top-left is at top-left */
  1392.  
  1393. void FixRect(Rect *rect)
  1394. {
  1395.     short pt;
  1396.     
  1397.     if (rect->left > rect->right) {
  1398.         pt = rect->left;
  1399.         rect->left = rect->right;
  1400.         rect->right = pt;
  1401.     }
  1402.  
  1403.     if (rect->top > rect->bottom) {
  1404.         pt = rect->top;
  1405.         rect->top = rect->bottom;
  1406.         rect->bottom = pt;
  1407.     }
  1408. }
  1409.  
  1410.  
  1411. /* offset shape by delta */
  1412.  
  1413. void OffsetShape(ShapeListPtr theShape,short deltaH,short deltaV)
  1414. {
  1415.     ShapeListPtr groupList;
  1416.     
  1417.     if (theShape->shapeType == kBeginGroupTag) {
  1418.         for (groupList=theShape->subList; groupList!=nil; groupList=groupList->next)
  1419.             OffsetShape(groupList,deltaH,deltaV);
  1420.     }
  1421.     
  1422.     theShape->anchor.h += deltaH;
  1423.     theShape->anchor.v += deltaV;
  1424.     theShape->destination.h += deltaH;
  1425.     theShape->destination.v += deltaV;
  1426. }
  1427.  
  1428.  
  1429. /* add a shape to the document */
  1430.  
  1431. ShapeListPtr AddShape(short currentShape,Point anchor,Point destination,ShapeListPtr subList,
  1432.                         ShapeListPtr *shapeHead,Boolean addToEnd)
  1433. {
  1434.     ShapeListPtr newShape;
  1435.     
  1436.     newShape = NewPtrChk(sizeof(ShapeList));
  1437.     if (MemError()!=noErr) {
  1438.         DoError(MemError());
  1439.         return nil;
  1440.     }
  1441.     
  1442.     // note: all of this funny business with "addToEnd" is to insure that the shapes are
  1443.     // not reversed during the save/load process so that any group digital signatures will still
  1444.     // remain valid
  1445.     
  1446.     if (addToEnd && *shapeHead) {
  1447.         (*shapeHead)->next = newShape;
  1448.         newShape->next = nil;
  1449.         *shapeHead = newShape;
  1450.     }
  1451.     else {
  1452.         newShape->next = *shapeHead;
  1453.         *shapeHead = newShape;
  1454.     }
  1455.     
  1456.     newShape->anchor = anchor;
  1457.     newShape->destination = destination;
  1458.     newShape->shapeType = currentShape;
  1459.     newShape->selected = false;
  1460.     newShape->isSigned = false;
  1461.     newShape->signatureID = 0;
  1462.     newShape->subList = subList;
  1463. }
  1464.  
  1465.  
  1466. /* set up the undo op.  we only support undo for adding shapes for now */
  1467.  
  1468. void AddShapeUndo(short currentShape,Point anchor,Point destination,WindowPtr window,
  1469.                     WInfoPtr infoPtr)
  1470. {
  1471.     ShapeList newShape;
  1472.     
  1473.     newShape.anchor = anchor;
  1474.     newShape.destination = destination;
  1475.     newShape.shapeType = currentShape;
  1476.     SetUndoCommand(window,infoPtr,&newShape);
  1477.     FixDrawMenus(infoPtr);
  1478. }
  1479.  
  1480.  
  1481. /* removes the top-most shape from the document (for undo) */
  1482.  
  1483. void RemoveTopShape(WindowPtr window,WInfoPtr infoPtr)
  1484. {
  1485.     ShapeList *shapeToKill,*shapeList;
  1486.     
  1487.     shapeList = (ShapeListPtr) infoPtr->data;
  1488.     shapeToKill = shapeList;
  1489.     InvalShapeArea(window,infoPtr,shapeToKill);
  1490.     
  1491.     infoPtr->data = shapeList->next;
  1492.     DisposPtrChk(shapeToKill);
  1493. }
  1494.  
  1495.  
  1496. /* forces a redraw of the area a shape occupies in the window (for when it has changed) */
  1497.  
  1498. void InvalShapeArea(WindowPtr window,WInfoPtr infoPtr,ShapeList *theShape)
  1499. {
  1500.     GrafPtr savePort;
  1501.     Rect shapeRect;
  1502.     Point *scrollPos;
  1503.     RgnHandle shapeRgn,scrollRgn;
  1504.     
  1505.     GetPort(&savePort);
  1506.     SetPort(window);
  1507.  
  1508.     SetRect(&shapeRect,theShape->anchor.h,theShape->anchor.v,
  1509.             theShape->destination.h,theShape->destination.v);
  1510.     FixRect(&shapeRect);
  1511.  
  1512.     scrollPos = (Point *)&infoPtr->otherData[kViewOffset];
  1513.     OffsetRect(&shapeRect,infoPtr->leftIndent-scrollPos->h,infoPtr->topIndent-scrollPos->v);
  1514.     InsetRect(&shapeRect,-5,-5);    // for slop
  1515.     shapeRgn = NewRgn();
  1516.     scrollRgn = GetScrollersRgn(&window->portRect);
  1517.     RectRgn(shapeRgn,&shapeRect);
  1518.     DiffRgn(shapeRgn,scrollRgn,shapeRgn);
  1519.     InvalRgn(shapeRgn);
  1520.     DisposeRgn(shapeRgn);
  1521.     DisposeRgn(scrollRgn);
  1522.     
  1523.     SetPort(savePort);
  1524. }
  1525.  
  1526.  
  1527. /* see how many shapes are selected */
  1528.  
  1529. short CheckShapeSelected(WInfoPtr infoPtr)
  1530. {
  1531.     ShapeListPtr shapeList;
  1532.     short shapeCount;
  1533.     
  1534.     shapeCount = 0;
  1535.     for (shapeList=infoPtr->data; shapeList!=nil; shapeList=shapeList->next) {
  1536.         if (shapeList->selected)
  1537.             shapeCount++;
  1538.     }
  1539.     return shapeCount;
  1540. }
  1541.  
  1542.  
  1543. /* see if a group is selected */
  1544.  
  1545. short CheckGroupSelected(WInfoPtr infoPtr)
  1546. {
  1547.     ShapeListPtr shapeList;
  1548.     
  1549.     for (shapeList=infoPtr->data; shapeList!=nil; shapeList=shapeList->next) {
  1550.         if (shapeList->selected && shapeList->shapeType==kBeginGroupTag)
  1551.             return true;
  1552.     }
  1553.     return false;
  1554. }
  1555.  
  1556.  
  1557. /* get the coordinate bounds of a group of shapes (for signing outline) */
  1558.  
  1559. void GetGroupBounds(ShapeListPtr groupList,Point *anchor,Point *destination)
  1560. {
  1561.     anchor->h = groupList->anchor.h;
  1562.     anchor->v = groupList->anchor.v;
  1563.     destination->h = groupList->destination.h;
  1564.     destination->v = groupList->destination.v;
  1565.     
  1566.     while (groupList) {
  1567.         if (groupList->anchor.h < anchor->h)
  1568.             anchor->h = groupList->anchor.h;
  1569.         if (groupList->destination.h < anchor->h)
  1570.             anchor->h = groupList->destination.h;
  1571.         if (groupList->anchor.v < anchor->v)
  1572.             anchor->v = groupList->anchor.v;
  1573.         if (groupList->destination.v < anchor->v)
  1574.             anchor->v = groupList->destination.v;
  1575.         if (groupList->anchor.h > destination->h)
  1576.             destination->h = groupList->anchor.h;
  1577.         if (groupList->destination.h > destination->h)
  1578.             destination->h = groupList->destination.h;
  1579.         if (groupList->anchor.v > destination->v)
  1580.             destination->v = groupList->anchor.v;
  1581.         if (groupList->destination.v > destination->v)
  1582.             destination->v = groupList->destination.v;
  1583.             
  1584.         groupList = groupList->next;
  1585.     }
  1586. }
  1587.  
  1588.  
  1589. /* save our document to a temporary file so we can send it within a letter */
  1590.  
  1591. OSErr SaveFileToTemp(WInfoPtr infoPtr,FSSpec *fSpec)
  1592. {
  1593.     OSErr err;
  1594.     long randNum;
  1595.     Str255 randStr;
  1596.     short fRefNum,resRefNum;
  1597.     
  1598.     err = FindFolder(kOnSystemDisk,kTemporaryFolderType,true,&fSpec->vRefNum,&fSpec->parID);
  1599.     if (err!=noErr)
  1600.         return err;
  1601.         
  1602.     randNum = (unsigned long) Random();
  1603.     NumToString(randNum,randStr);
  1604.     pstrcpy(fSpec->name,randStr);
  1605.     
  1606.     // create the temporary file
  1607.     
  1608.     err = FSpCreate(fSpec,kAppCreator,kDrawingType,smRoman);
  1609.     if (err==dupFNErr) {
  1610.         FSpDelete(fSpec);
  1611.         err = FSpCreate(fSpec,kAppCreator,kDrawingType,smRoman);
  1612.     }
  1613.     if (err!=noErr) {
  1614.         FSpDelete(fSpec);
  1615.         return err;
  1616.     }
  1617.     FSpCreateResFile(fSpec,kAppCreator,kDrawingType,smRoman);
  1618.     err = ResError();
  1619.     if (err!=noErr) {
  1620.         FSpDelete(fSpec);
  1621.         return err;
  1622.     }
  1623.     
  1624.     // open the temporary file
  1625.     
  1626.     err = FSpOpenDF(fSpec,fsRdWrPerm,&fRefNum);
  1627.     if (err!=noErr) {
  1628.         FSpDelete(fSpec);
  1629.         return err;
  1630.     }
  1631.     resRefNum = FSpOpenResFile(fSpec,fsRdWrPerm);
  1632.     err = ResError();
  1633.     if (err!=noErr) {
  1634.         FSClose(fRefNum);
  1635.         FSpDelete(&infoPtr->fileSpec);
  1636.         return err;
  1637.     }
  1638.     
  1639.     // save the digital signature information
  1640.     
  1641.     DSIGSaveFile(infoPtr,resRefNum,true);
  1642.     
  1643.     // save the data into the temporary file
  1644.     
  1645.     err = SaveDrawingToDisk(fRefNum,infoPtr);
  1646.  
  1647.     // close the file
  1648.     
  1649.     FSClose(fRefNum);
  1650.     CloseResFile(resRefNum);
  1651.     
  1652.     if (err!=noErr) {
  1653.         FSpDelete(fSpec);
  1654.     }
  1655.  
  1656.     return err;
  1657. }
  1658.  
  1659.  
  1660. /* save our drawing document to an open disk file pointed to by fRefNum */
  1661.  
  1662. OSErr SaveDrawingToDisk(short fRefNum,WInfoPtr infoPtr)
  1663. {
  1664.     OSErr err;
  1665.     ShapeListPtr shapeList;
  1666.     long count,totalCount;
  1667.     char hState;
  1668.     
  1669.     // set file position to start of file
  1670.     
  1671.     err = SetFPos(fRefNum,fsFromStart,0);
  1672.     if (err!=noErr)
  1673.         return err;
  1674.     totalCount = 0;
  1675.     
  1676.     // write print record
  1677.     
  1678.     count = sizeof(TPrint);
  1679.     hState = HGetState((Handle)infoPtr->printRecord);
  1680.     HLock((Handle)infoPtr->printRecord);
  1681.     err = FSWrite(fRefNum,&count,*(infoPtr->printRecord));
  1682.     totalCount += count;
  1683.     HSetState((Handle)infoPtr->printRecord,hState);
  1684.     if (err!=noErr)
  1685.         return err;
  1686.     
  1687.     // write shape information
  1688.     
  1689.     shapeList = infoPtr->data;
  1690.     err = SaveShapesToDisk(fRefNum,infoPtr->data,&totalCount);
  1691.     if (err!=noErr)
  1692.         return err;
  1693.         
  1694.     // set file length
  1695.     
  1696.     err = SetEOF(fRefNum,totalCount);
  1697.     
  1698.     return err;
  1699. }
  1700.  
  1701.  
  1702. /* save a list of shapes to a disk file pointed to by fRefNum */
  1703. /* may be called recursively for groups */
  1704.  
  1705. OSErr SaveShapesToDisk(short fRefNum,ShapeListPtr shapeList,long *totalCount)
  1706. {
  1707.     long count;
  1708.     OSErr err;
  1709.     
  1710.     while (shapeList) {
  1711.         count = sizeof(ShapeList);
  1712.         err = FSWrite(fRefNum,&count,shapeList);
  1713.         *totalCount += count;
  1714.         if (err!=noErr) {
  1715.             return err;
  1716.         }
  1717.         if (shapeList->shapeType==kBeginGroupTag) {
  1718.             err = SaveShapesToDisk(fRefNum,shapeList->subList,totalCount);
  1719.             if (err!=noErr)
  1720.                 return err;
  1721.             count = sizeof(ShapeList);
  1722.             shapeList->shapeType = kEndGroupTag;
  1723.             err = FSWrite(fRefNum,&count,shapeList);
  1724.             *totalCount += count;
  1725.             shapeList->shapeType = kBeginGroupTag;
  1726.         }
  1727.         
  1728.         shapeList = shapeList->next;
  1729.     }
  1730.     return err;
  1731. }
  1732.  
  1733.  
  1734. /* load a list of shapes from a disk file pointed to by fRefNum */
  1735. /* may be called recursively for groups */
  1736.  
  1737. OSErr LoadShapesFromDisk(short fRefNum,ShapeListPtr *shapeHead)
  1738. {
  1739.     long count;
  1740.     OSErr err;
  1741.     ShapeList theShape;
  1742.     ShapeListPtr newShape,endShape;
  1743.     
  1744.     endShape = *shapeHead;
  1745.     
  1746.     do {
  1747.         count = sizeof(ShapeList);
  1748.         err = FSRead(fRefNum,&count,&theShape);
  1749.         if (err==noErr) {
  1750.             if (theShape.shapeType==kBeginGroupTag) {
  1751.                 theShape.subList = nil;
  1752.                 err = LoadShapesFromDisk(fRefNum,&theShape.subList);
  1753.                 if (err==noErr) {
  1754.                     newShape = AddShape(theShape.shapeType,theShape.anchor,theShape.destination,
  1755.                                     theShape.subList,&endShape,true);
  1756.                     newShape->isSigned = theShape.isSigned;
  1757.                     newShape->signatureID = theShape.signatureID;
  1758.                 }
  1759.             }
  1760.             else if (theShape.shapeType!=kEndGroupTag) {
  1761.                 newShape = AddShape(theShape.shapeType,theShape.anchor,theShape.destination,
  1762.                                     nil,&endShape,true);
  1763.                 newShape->isSigned = theShape.isSigned;
  1764.                 newShape->signatureID = theShape.signatureID;
  1765.             }
  1766.             if (*shapeHead==nil)
  1767.                 *shapeHead = endShape;
  1768.         }
  1769.     } while (err==noErr && theShape.shapeType!=kEndGroupTag);
  1770.     return err;
  1771. }
  1772.  
  1773.  
  1774. /* fix up the drawing menu items when the state of the document has changed */
  1775.  
  1776. void FixDrawMenus(WInfoPtr infoPtr)
  1777. {
  1778.     MenuHandle theMenu;
  1779.     
  1780.     FixDrawEditMenu();
  1781.     
  1782.     theMenu = GetMHandle(kShapesMenu);
  1783.     EnableAllMenuItems(theMenu);
  1784.     if (CheckShapeSelected(infoPtr)<2)
  1785.         DisableItem(theMenu,kGroupItem);
  1786.     if (!CheckGroupSelected(infoPtr))
  1787.         DisableItem(theMenu,kUngroupItem);
  1788.  
  1789.     DSIGSetupSignMenu(infoPtr);
  1790.     
  1791.     gMenusDirty = true;
  1792. }
  1793.  
  1794.  
  1795. /* fix up the edit menu items when the state of the document has changed */
  1796.  
  1797. void FixDrawEditMenu(void)
  1798. {
  1799.     MenuHandle theMenu;
  1800.  
  1801.     theMenu = GetMHandle(kEditMenu);
  1802.     EnableAllMenuItems(theMenu);
  1803.     if (!SetupAppUndo())
  1804.         DisableItem(theMenu,kUndoItem);
  1805.     DisableItem(theMenu,kCutItem);
  1806.     DisableItem(theMenu,kCopyItem);
  1807.     DisableItem(theMenu,kPasteItem);
  1808.     DisableItem(theMenu,kClearItem);
  1809. }